package src.cs2340.todoApp;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
/**
 * @version 1.0 March 19, 2012
 * This is going to test Database.  Assmume that Account and all its methods/subclasses
 * and dependencies are already working properly from a previous test.
 *
 * Do Test Account before testing the Database as a whole.
 */
public class DatabaseTest {

	Database db, db2;

	@Before
	public void setUp() throws Exception {
		db = Database.getInstance();
		db2 = Database.getInstance();
	}

	/**
	 * @author Rochelle
	 * Will test Database's login method using Database 1.  Database 2 will test the
	 * AddAccount method using the Login method here for Database 2.  If AddAccount's giving
	 * problems, this test will tell you whether that bug occurs in the login method or
	 * somewhere else.
	 *
	 * @throws AddAccountException
	 */
	@Test
	public void testLogin() throws AddAccountException
	{
		Account accK = new Account("Kristian.E64", "password2", "Kristian", "keberhardson3@gatech.edu", db);
		Account accJ = new Account("Aizent", "password", "Jordan", "aizent@gmail.com", db);
		Account accRoc = new Account("Rochelle", "password", "Rochelle", "rochelle.l.lobo@gmail.com", db);
		Account accRah = new Account("Rahul", "password", "Rahul", "r.sheth38@gmail.com", db);

		assertFalse("We haven't registered anyone yet.", db.login(accK));
		assertFalse("We haven't registered anyone yet.", db.login(accJ));
		assertFalse("We haven't registered anyone yet.", db.login(accRoc));
		assertFalse("We haven't registered anyone yet.", db.login(accRah));

		try
		{
			accK.register();
	    } catch (AddAccountException aae) {
	    	aae.printStackTrace();
	    }

		try
		{
			accJ.register();
	    } catch (AddAccountException aae) {
	    	aae.printStackTrace();
	    }

		assertTrue(db.login(accK));
		assertTrue(db.login(accJ));
		assertFalse(db.login(accRoc));
		assertFalse(db.login(accRah));

		try
		{
			accK.register();
	        assertTrue("You failed to throw the exception properly for Kristian" +
	                "trying to register again.", false);
	    } catch (AddAccountException aae) {
	         assertTrue(true);

	         /*if a whole bunch of errors print to the console, then
	         the stack trace is printing properly.*/
	         aae.printStackTrace();
	      }

		try
		{
			accRoc.register();
	    } catch (AddAccountException aae) {
	    	aae.printStackTrace();
	    }

		try
		{
			accRah.register();
	    } catch (AddAccountException aae) {
	    	aae.printStackTrace();
	    }

		assertTrue("By now, everyone's registered.", db.login(accK));
		assertTrue("By now, everyone's registered.", db.login(accJ));
		assertTrue("By now, everyone's registered.", db.login(accRoc));
		assertTrue("By now, everyone's registered.", db.login(accRah));
	}

 	/**
 	 * @author Rochelle
 	 * Testing 4 accounts to make sure they get added to the database.  Then, making sure
 	 * that database.login returns true to recognize these accounts.
 	 * @throws AddAccountException
	 */
	@Test
	public void testAddAccount() throws AddAccountException
	{
		Account accK2 = new Account("keberhardson", "password2", "Kristian", "keberhardson3@gatech.edu", db2);
		Account accJ2 = new Account("jmayhue", "password", "Jordan", "aizent@gmail.com", db2);
		Account accRoc2 = new Account("rLobo3", "password", "Rochelle", "rochelle.l.lobo@gmail.com", db2);
		Account accRah2 = new Account("r.sheth", "password", "Rahul", "r.sheth38@gmail.com", db2);

		//Does database recognize this account yet?  It shouldn't.
		assertFalse(db2.login(accK2));

		//adding Kristian's account
		db2.addAccount(accK2);

		//NOW it should be true for Kristian logging in.
		assertTrue(db2.login(accK2));


		//it has yet to add more though, so it should print false because it doesn't recognize them.
		assertFalse(db2.login(accJ2));
		assertFalse(db2.login(accRoc2));
		assertFalse(db2.login(accRah2));

		//adding Jordan's and Rochelle's accounts
		db2.addAccount(accJ2);
		db2.addAccount(accRoc2);

		//testing new accounts
		assertTrue(db2.login(accJ2));
		assertTrue(db2.login(accRoc2));

		//does it still recognize Kristian's account?
		assertTrue(db2.login(accK2));

		//should be false because Rahul has yet to register.
		assertFalse(db2.login(accRah2));

		//adding Rahul's account
		db2.addAccount(accRah2);

		//Rahul should now be in the database.
		assertTrue(db2.login(accRah2));

		//the other accounts should still be in the database
		assertTrue(db2.login(accK2));
		assertTrue(db2.login(accJ2));
		assertTrue(db2.login(accRoc2));
	}

	/**
	 * @author Rochelle
	 * Recreating the accounts already existing in the database.  Will try
	 * (and fail, if the AddAccountException is working) to add an already
	 * existing account to the Database.  Then, will update the accounts in
	 * database with these newly created ones.
	 *
	 * Will create 3 taskItems and try to add these to the accounts to
	 * make sure the accounts are getting the tasks and running well.
	 *
	 * In the end, makes sure update is doing its
	 * job by checking the account in Database and making sure it is equal
	 * to the local account variable.
	 */
	@Test
	public void testUpdate()
	{
		//initializing same accounts as in previous tests to test different methods. :)
		//since they already exist in the database, we can simply update them.
		Account accK = new Account("Kristian.E64", "password2", "Kristian", "keberhardson3@gatech.edu", db);
		Account accJ = new Account("Aizent", "password", "Jordan", "aizent@gmail.com", db);
		Account accRoc = new Account("Rochelle", "password", "Rochelle", "rochelle.l.lobo@gmail.com", db);
		Account accRah = new Account("Rahul", "password", "Rahul", "r.sheth38@gmail.com", db);

		//make sure an exception is thrown when I try to add the account to the database again.
		 try
		 {
			 db.addAccount(accK);
	         assertTrue("You failed to throw the exception properly for adding an already" +
	                 "existing account.", false);
	     } catch (AddAccountException aae) {
	         assertTrue(true);

	         /*if a whole bunch of errors print to the console, then
	         the stack trace is printing properly.*/
	         aae.printStackTrace();
	       }

		db.update(accK);
		db.update(accJ);
		db.update(accRoc);
		db.update(accRah);

		Date date1 = new Date(27, 3, 2012, 30, 18, Date.Meredian.AM);//6:30pm March 27, 2012
		Location loc1 = new Location("GA Tech", 1400, "Ferst Lane", "Atlanta", "GA",
				30309);//Georgia Tech 1400 Ferst Lane, Atlanta, GA, 30309
		TaskItem task1 = new TaskItem("m9", loc1, date1, "do JUnit tests", "cs2340", false);

		Date date2 = new Date(21, 12, 2012, 0, 0, Date.Meredian.PM);//12-21-2012 midnight
		Location loc2 = new Location("Zanzibar Island", 666, "Devil's Lane", "Idontknow",
				"FL", 66661);
		TaskItem task2 = new TaskItem("end the world", loc2, date2, "It's the end" +
				"of the Mayan calandar baby!!", "CthuluStuff", false);

		//can the same date/location be used again in a different task? I believe so...
		TaskItem task3 = new TaskItem("stop Cthulu", loc2, date2, "Stop Cthulu from" +
				"ending the world", "Be-A-Hero", false);

		accK.addTaskItem(task1);
		db.update(accK);
		assertEquals("has the Account in Database been updated with accK?",
				db.getUpdate(accK), accK);

		//make sure the same task can be used in two different accounts
		accK.addTaskItem(task2);
		db.update(accK);
		assertEquals("has the Account in Database been updated with the newly revised acck?",
				db.getUpdate(accK), accK);

		accJ.addTaskItem(task2);
		db.update(accJ);
		assertEquals("has Jordan's account in Database been updated with the local variable?",
				db.getUpdate(accJ), accJ);

		//make sure the same person can have 2 tasks in the same location/date/category
		accJ.addTaskItem(task3);
		db.update(accJ);
		assertEquals("If these two accounts are unequal, then update isn't updating accounts" +
				"already containing tasks with new tasks", db.getUpdate(accJ), accJ);

		//then give someone else the same task
		accRoc.addTaskItem(task3);
		accRah.addTaskItem(task3);

		db.update(accRoc);
		db.update(accRah);

		assertEquals("Can Rochelle's account be updated with a the same task as Jordan's " +
				"account?", db.getUpdate(accRoc), accRoc);
		assertEquals("Can Rahul's account in Database be updated with the same new task?",
				db.getUpdate(accRah), accRah);
	}

	/**
	 * @author Jordan
	 * This test makes sure I get the accounts I mean to get, lest getUpdate doesn't work properly.
	 * If it does, then we'll know update fails if the test above fails.
	 */
	@Test
	public void getUpdate()
	{
		//initializing same accounts as in previous tests to test different methods. :)
		//since they already exist in the database, we can simply update them.
		Account accK = new Account("Kristian.E64", "password2", "Kristian", "keberhardson3@gatech.edu", db);
		Account accJ = new Account("Aizent", "password", "Jordan", "aizent@gmail.com", db);
		Account accRoc = new Account("Rochelle", "password", "Rochelle", "rochelle.l.lobo@gmail.com", db);
		Account accRah = new Account("Rahul", "password", "Rahul", "r.sheth38@gmail.com", db);
		Account pikachu = new Account("Pikachu", "password", "Pikachu", "electric@Tail.com", db);
		
		assertNull("I haven't this account to Database 1 yet.", db.getUpdate(pikachu));
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accK)
				, accK);
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accJ)
				, accJ);
		
		try
		 {
			 db.addAccount(accK);
	         assertTrue("You failed to throw the exception properly for adding an already" +
	                 "existing account.", false);
	     } catch (AddAccountException aae) {
	         assertTrue(true);

	         /*if a whole bunch of errors print to the console, then
	         the stack trace is printing properly.*/
	         aae.printStackTrace();
	       }
		
		try
		{
			db.addAccount(pikachu);
	    } catch (AddAccountException aae) {
	    	aae.printStackTrace();
	    }
		
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accK)
				, accK);
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accJ)
				, accJ);
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accRoc)
				, accRoc);
		assertEquals("I can still get all the other account updates though...", db.getUpdate(accRah)
				, accRah);
		assertEquals("I can still get all the other account updates though...", db.getUpdate(pikachu)
				, pikachu);
    }
}
